package service

import (
	"context"
	"database/sql"
	"encoding/json"
	"errors"
	"gf/app/dao"
	"gf/app/model"
	"gf/library/common"
	"gf/library/elastic"
	"github.com/gogf/gf/frame/g"
	"gopkg.in/guregu/null.v3"
	"net/url"
	"strconv"
	"strings"
)

var Article = articleService{}

type articleService struct{}

func (s *articleService) Add(ctx context.Context, data *model.ArticleApiReq) (int64, error) {
	var articleCategory *articleCategoryService
	category, err := articleCategory.Info(ctx, int64(data.CategoryId))
	if err != nil {
		return 0, err
	}
	if category == nil{
		return 0, errors.New("分类不存在")
	}

	tx, err := g.DB().Begin()
	if err != nil {
		return 0, err
	}
	defer func() {
		if err != nil {
			_ = tx.Rollback()
		} else {
			_ = tx.Commit()
		}
		_ = tx.Rollback()
	}()

	id, err := dao.GfArticle.Ctx(ctx).
		TX(tx).
		Data(g.Map{"title": data.Title, "content": data.Content, "category_id": data.CategoryId}).
		InsertAndGetId()
	if err != nil {
		return 0, err
	}

	var articleMap map[string]interface{}
	articleMap = make(map[string]interface{})

	articleMap["title"] = data.Title
	articleMap["content"] = data.Content
	articleMap["category_id"] = data.CategoryId
	articleMap["updated_at"] = common.IsoToDate()
	articleMap["created_at"] = common.IsoToDate()
	articleMap["deleted_at"] = null.Time{}

	_, err = elastic.Create(elastic.ArticleIndex, articleMap, strconv.Itoa(int(id)))
	if err != nil {
		return 0, err
	}

	return id, nil
}

func (s *articleService) Del(ctx context.Context, data *model.ArticleApiInfoReq) (sql.Result, error) {
	tx, err := g.DB().Begin()
	if err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			_ = tx.Rollback()
		} else {
			_ = tx.Commit()
		}
	}()

	result, err := dao.GfArticle.
		Ctx(ctx).
		TX(tx).
		Where("id=? ", data.Id).
		Delete()
	if err != nil {
		return nil, err
	}

	var articleMap map[string]interface{}
	articleMap = make(map[string]interface{})

	articleMap["deleted_at"] = common.IsoToDate()

	_, err = elastic.Put(elastic.ArticleIndex, articleMap, strconv.Itoa(data.Id))
	if err != nil {
		return nil, err
	}

	return result, nil
}

func (s *articleService) Info(ctx context.Context, data *model.ArticleApiInfoReq) (*model.Article, error) {
	var article *model.Article
	var articleCategory *articleCategoryService

	err := dao.GfArticle.Ctx(ctx).Where("id", data.Id).Scan(&article)
	if err != nil {
		return nil, err
	}
	if article == nil {
		return article, nil
	}

	category, err := articleCategory.Info(ctx, article.CategoryId)
	if err == nil {
		article.CategoryName = category.Name
	}

	return article, nil
}


func (s *articleService) Edit(ctx context.Context, data *model.ArticleApiSaveReq) (sql.Result, error) {
	var articleCategory *articleCategoryService

	category, err := articleCategory.Info(ctx, int64(data.CategoryId))
	if err != nil {
		return nil, err
	}
	if category == nil{
		return nil, errors.New("分类不存在")
	}

	tx, err := g.DB().Begin()
	if err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			_ = tx.Rollback()
		} else {
			_ = tx.Commit()
		}
	}()

	result, err := dao.GfArticle.Ctx(ctx).
		TX(tx).
		Where("id=? ", data.Id).
		Data(g.Map{"title": data.Title, "content": data.Content, "category_id": data.CategoryId}).
		Update()
	if err != nil {
		return nil, err
	}

	var articleMap map[string]interface{}
	articleMap = make(map[string]interface{})

	articleMap["title"] = data.Title
	articleMap["content"] = data.Content
	articleMap["category_id"] = data.CategoryId
	articleMap["updated_at"] = common.IsoToDate()

	_, err = elastic.Put(elastic.ArticleIndex, articleMap, strconv.Itoa(data.Id))
	if err != nil {
		return nil, err
	}

	return result, nil
}

type EsQueryMap struct {
	Query EsQueryMapQuery
}

type EsQueryMapQuery struct {
	BoolName  string
	BoolValue interface{}
}

func (s *articleService) List(ctx context.Context, input model.ArticleGetListInput) (output *model.ArticleGetListOutput, err error) {
	output = &model.ArticleGetListOutput{
		Page: input.Page,
		Size: input.Size,
	}

	if input.Page <= 0 {
		input.Page = 1
	}

	if input.Size <= 0 {
		input.Size = 10
	}

	where := ""
	input.Keywords, _ = url.QueryUnescape(input.Keywords)

	if input.Keywords != "" {
		where += `{
			"multi_match" : {
				  "query" :  "` + input.Keywords + `",
				  "fields": ["title", "content"]
			  }
			},`
	}
	if input.CategoryId > 0 {
		where += `{
			"match_phrase": {
					"category_id":  ` + strconv.Itoa(input.CategoryId) + `
				}
			},`
	}

	notWhere := `   
		"must_not": [
			{
				"exists": {
                    "field": "deleted_at"
                }
			}
		  ]`

	where = strings.Trim(where, ",")
	from := (input.Page - 1) * input.Size
	query := `{
	  	"query": {
			"bool": {
				"must": [
			  	` + where + `
				],
				` + notWhere + `
			}
	  	},
		"highlight": {
			"fields": {
				"content":{
					 "type": "unified"
				},
				"title":{
					 "type": "unified"
				}
			},
			"pre_tags": ["<font color='red'>"],
    		"post_tags": ["</font>"]
		},
    	"_source": ["id","title","content","category_id","created_at","updated_at","deleted_at"],
		"sort": [
			{
			  "id": "desc"
			}
		],
	  	"from": ` + strconv.Itoa(from) + `,
	  	"size":  ` + strconv.Itoa(input.Size) + `
	}`

	//g.Dump(query)

	list, err := elastic.Search(elastic.ArticleIndex, query)
	if err != nil {
		return nil, err
	}

	var esData elastic.EsData
	err = json.Unmarshal([]byte(list), &esData)
	if err != nil {
		return nil, err
	}

	var articleCategory *articleCategoryService
	for k, v := range esData.Hits.Hits {
		category, err2 := articleCategory.Info(ctx, v.Source.CategoryId)
		if err2 == nil && category != nil {
			esData.Hits.Hits[k].Source.CategoryName = category.Name
		}
	}

	output.Total = esData.Hits.Total.Value
	output.Count = len(esData.Hits.Hits)
	output.Result = esData.Hits.Hits

	return output, nil

	//db := g.DB()
	//// 开启调试模式，以便于记录所有执行的SQL
	//db.SetDebug(true)

	//m := dao.GfArticle.Ctx(ctx).As("a")
	//
	////文章分类筛选
	//if input.CategoryId > 0 {
	//	var articleCategory *model.ArticleCategory
	//	err := dao.GfArticleCategory.Ctx(ctx).Where("id=? ", input.CategoryId).Scan(&articleCategory)
	//	if articleCategory == nil {
	//		return nil, errors.New("分类不存在")
	//	}
	//	if err != nil {
	//		return nil, err
	//	}
	//
	//	m.Where("a.category_id=? ", input.CategoryId)
	//}
	//
	//err = m.Page(input.Page, input.Size).
	//	Fields("a.*,c.name categoryName").
	//	OrderDesc("a.id").
	//	LeftJoin("article_category", "c", "c.id=a.category_id").
	//	ScanList(&output.List, "Article")
	//
	//if err != nil {
	//	return nil, err
	//}

	//output.Total, _ = m.Count()
	//output.Count = len(output.List)

}
